//
//  GameEngine.m
//  iMine
//
//  Created by gaoxiang on 09-3-8.
//  Copyright 2009 __MyCompanyName__. All rights reserved.
//

#import "GameEngine.h"

static GameEngine *_instance;

@implementation GameEngine
@synthesize level, rows, cols, elapseSecond, mineNumber, materialImage, secondConterImage, remainConterImage, materialCache, mineFieldImage, gameStarted, gameIsOver;

#pragma mark 静态方法
+ (GameEngine *)sharedGameEngine {
    if (!_instance) {
        _instance = [[[self class] alloc] initAndLoadResources];
    }
    return _instance;
}

#pragma mark 初始化方法
- (id) initAndLoadResources {
	if ([super init])
	{
		gameStarted = NO;
		level = MINE_LEVEL1;
		rows = MINE_LEVEL1_ROWS;
		cols = MINE_LEVEL1_COLS;
		mineNumber = MINE_LEVEL1_NUMBER;
		
		fieldData = NULL;
		currentRows = 0;
		currentRows = 0;
		
		nonMineFieldCheckedCount = 0;
		materialImage = nil;
		mineFieldImage = nil;
		minePositions = nil;
		
		secondConterImage = [[NSImage alloc] initWithSize:NSMakeSize(60, 40)];
		[secondConterImage lockFocus];
		[[NSColor blackColor] set];
		[NSBezierPath fillRect:NSMakeRect(0, 0, 60, 40)];
		[secondConterImage unlockFocus];
		
		remainConterImage = [[NSImage alloc] initWithSize:NSMakeSize(60, 40)];
		
		//materialImage = [[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:@"iMineImage"]];
		materialImage = [NSImage imageNamed:@"iMineImage"];
		//[[materialImage copy] retain];
		if (materialImage)
		{
			materialCache = [[NSMutableDictionary alloc] init];
			[materialCache setValue:[NSValue valueWithRect:NSMakeRect(1, 1, 16, 16)] forKey:MINEFIELD_KEY_ZERO];
			[materialCache setValue:[NSValue valueWithRect:NSMakeRect(19, 1, 16, 16)] forKey:MINEFIELD_KEY_ONE];
			[materialCache setValue:[NSValue valueWithRect:NSMakeRect(37, 1, 16, 16)] forKey:MINEFIELD_KEY_TWO];
			[materialCache setValue:[NSValue valueWithRect:NSMakeRect(55, 1, 16, 16)] forKey:MINEFIELD_KEY_THREE];
			[materialCache setValue:[NSValue valueWithRect:NSMakeRect(73, 1, 16, 16)] forKey:MINEFIELD_KEY_FOUR];
			[materialCache setValue:[NSValue valueWithRect:NSMakeRect(91, 1, 16, 16)] forKey:MINEFIELD_KEY_FIVE];
			[materialCache setValue:[NSValue valueWithRect:NSMakeRect(109, 1, 16, 16)] forKey:MINEFIELD_KEY_SIX];
			[materialCache setValue:[NSValue valueWithRect:NSMakeRect(127, 1, 16, 16)] forKey:MINEFIELD_KEY_SEVEN];
			[materialCache setValue:[NSValue valueWithRect:NSMakeRect(145, 1, 16, 16)] forKey:MINEFIELD_KEY_EIGHT];
			[materialCache setValue:[NSValue valueWithRect:NSMakeRect(163, 1, 16, 16)] forKey:MINEFIELD_KEY_NINE];
			[materialCache setValue:[NSValue valueWithRect:NSMakeRect(0, 20, 20, 20)] forKey:MINEFIELD_KEY_BLANK];
			[materialCache setValue:[NSValue valueWithRect:NSMakeRect(21, 20, 20, 20)] forKey:MINEFIELD_KEY_BLOCK];
			//[materialCache setValue:[NSValue valueWithRect:NSMakeRect(42, 20, 20, 20)] forKey:MINEFIELD_KEY_MINE];
			[materialCache setValue:[NSValue valueWithRect:NSMakeRect(105, 20, 20, 20)] forKey:MINEFIELD_KEY_MINE];
			[materialCache setValue:[NSValue valueWithRect:NSMakeRect(126, 20, 20, 20)] forKey:MINEFIELD_KEY_MINECRASH];
			[materialCache setValue:[NSValue valueWithRect:NSMakeRect(63, 20, 20, 20)] forKey:MINEFIELD_KEY_FLAG];
			[materialCache setValue:[NSValue valueWithRect:NSMakeRect(84, 20, 20, 20)] forKey:MINEFIELD_KEY_REDX];
			
			
			[materialCache setValue:[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:NUMBER_KEY_MINUS]] forKey:NUMBER_KEY_MINUS];
			[materialCache setValue:[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:NUMBER_KEY_ZERO]] forKey:NUMBER_KEY_ZERO];
			[materialCache setValue:[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:NUMBER_KEY_ONE]] forKey:NUMBER_KEY_ONE];
			[materialCache setValue:[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:NUMBER_KEY_TWO]] forKey:NUMBER_KEY_TWO];
			[materialCache setValue:[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:NUMBER_KEY_THREE]] forKey:NUMBER_KEY_THREE];
			[materialCache setValue:[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:NUMBER_KEY_FOUR]] forKey:NUMBER_KEY_FOUR];
			[materialCache setValue:[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:NUMBER_KEY_FIVE]] forKey:NUMBER_KEY_FIVE];
			[materialCache setValue:[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:NUMBER_KEY_SIX]] forKey:NUMBER_KEY_SIX];
			[materialCache setValue:[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:NUMBER_KEY_SEVEN]] forKey:NUMBER_KEY_SEVEN];
			[materialCache setValue:[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:NUMBER_KEY_EIGHT]] forKey:NUMBER_KEY_EIGHT];
			[materialCache setValue:[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:NUMBER_KEY_NINE]] forKey:NUMBER_KEY_NINE];
			[materialCache setValue:[[NSImage alloc] initWithContentsOfFile:[[NSBundle mainBundle] pathForImageResource:NUMBER_KEY_INACTIVE]] forKey:NUMBER_KEY_INACTIVE];
		}
		
		
		NSLog(@"GameEngine Init Finish");
	}
	
	return self;
}
- (void)dealloc {
	[self releaseFieldData];
	[secondConterImage release];
	[remainConterImage release];
	[materialImage release];
	[materialCache release];
	//[mineField release];
	[mineFieldImage release];
	if (minePositions)
		[minePositions release];
	[super dealloc];
}

#pragma mark 属性操作
- (int)flagMineCount {
	return flagMineCount;
}
- (void)setFlagMineCount:(int)count {
	flagMineCount = count;
	NSString *numstr = [NSString stringWithFormat:@"%03d", flagMineCount];
	
	NSRect drawingRect;
	drawingRect.origin.y = 0;
	drawingRect.size.width = 20;
	drawingRect.size.height = 40;
	
	[remainConterImage lockFocus];
	
	[[NSColor blackColor] set];
	[NSBezierPath fillRect:NSMakeRect(0, 0, 60, 40)];
	
	for (int i = 0; i < [numstr length]; i++)
	{
		drawingRect.origin.x = i * 20;
		
		NSString *key = [NSString stringWithFormat:@"red%@", [numstr substringWithRange:NSMakeRange(i, 1)]];
		NSImage *image = (NSImage *)[materialCache objectForKey:key];
		
		[image drawInRect:drawingRect
				 fromRect:NSMakeRect(0, 0, [image size].width, [image size].height)
				operation:NSCompositeSourceOver 
				 fraction:1];
	}
	[remainConterImage unlockFocus];
	[self postNotificationForKey:@"remainCounterChanged"];
}
- (void)increaseFlagMineCount {
	[self setFlagMineCount:flagMineCount + 1];
}
- (void)decreaseFlagMineCount {
	[self setFlagMineCount:flagMineCount - 1];
}
- (int) getElapseSecond {
	return elapseSecond;
}
- (void) increaseElapseSecond:(id)object {
	elapseSecond++;
	
	if (elapseSecond > 999) return;
	
	NSString *numstr = [NSString stringWithFormat:@"%03d", elapseSecond];
	
	NSRect drawingRect;
	drawingRect.origin.y = 0;
	drawingRect.size.width = 20;
	drawingRect.size.height = 40;
	
	[secondConterImage lockFocus];
	
	[[NSColor blackColor] set];
	[NSBezierPath fillRect:NSMakeRect(0, 0, 60, 40)];
	
	for (int i = 0; i < [numstr length]; i++)
	{
		drawingRect.origin.x = i * 20;
		
		NSString *key = [NSString stringWithFormat:@"red%@", [numstr substringWithRange:NSMakeRange(i, 1)]];
		NSImage *image = (NSImage *)[materialCache objectForKey:key];
		
		[image drawInRect:drawingRect
				 fromRect:NSMakeRect(0, 0, [image size].width, [image size].height)
				operation:NSCompositeSourceOver 
				 fraction:1];
	}
	[secondConterImage unlockFocus];
	[self postNotificationForKey:@"secoundCounterChanged"];
}

#pragma mark 游戏控制
- (void)testMineField {	
	for (int i = 0; i < currentCols; i++)
	{
		for (int j = 0; j < currentRows; j++)
		{
			int x = i;
			int y = j;
			NSRect drawingRect;
			drawingRect.size = NSMakeSize(MineFieldWidth, MineFieldHeight);
			drawingRect.origin.x = x * MineFieldWidth;
			drawingRect.origin.y = y * MineFieldHeight;
			
			NSRect imageRect = [(NSValue *)[materialCache objectForKey:[self imageKeyForPoint:x andYAxis:y]] rectValue];
			
			[mineFieldImage lockFocus];
			
			// 画地雷和数字前，需要先把空地方画上去
			[materialImage drawInRect:drawingRect fromRect:[(NSValue *)[materialCache objectForKey:MINEFIELD_KEY_BLANK] rectValue] operation:NSCompositeSourceOver fraction:1];
			
			//设置雷区格子大小和位置
			if (![self isSignForField:FSMineField atXAxis:x andYAxis:y] && [self getAroundMineCountAtPoint:x andYAxis:y] > 0)
			{
				// 如果周围数量大于0
				drawingRect.size = NSMakeSize(MineFieldNumberWidth, MineFieldNumberHeight);
				drawingRect.origin.x = x * MineFieldWidth + 2;
				drawingRect.origin.y = y * MineFieldHeight + 3;
			}
			if ([self isSignForField:FSMineField atXAxis:x andYAxis:y] || [self getAroundMineCountAtPoint:x andYAxis:y] > 0)
				[materialImage drawInRect:drawingRect fromRect:imageRect operation:NSCompositeSourceOver fraction:1];
			
			[mineFieldImage unlockFocus];
		}
	}
}
// 新游戏
- (void) newGame {
	if (level == MINE_LEVEL1)
	{
		cols = MINE_LEVEL1_COLS;
		rows = MINE_LEVEL1_ROWS;
		mineNumber = MINE_LEVEL1_NUMBER;
	}
	else if (level == MINE_LEVEL2)
	{
		cols = MINE_LEVEL2_COLS;
		rows = MINE_LEVEL2_ROWS;
		mineNumber = MINE_LEVEL2_NUMBER;
	}
	else if (level == MINE_LEVEL3)
	{
		cols = MINE_LEVEL3_COLS;
		rows = MINE_LEVEL3_ROWS;
		mineNumber = MINE_LEVEL3_NUMBER;
	}
	
	[self mineInField:NSMakeSize(cols, rows)];
}
// 新的自定义游戏
- (void) newCustomGame:(int)row withColumn:(int)col withMineNumber:(int)number {
	level = MINE_LEVEL_CUSTOM;
	cols = col;
	rows = row;
	mineNumber = number;
	NSSize size;
	size.width = cols;
	size.height = rows;
	[self mineInField:size];
}
- (void)setGameOver:(BOOL)isWin {
	gameIsOver = YES;
	[self turnOffStopWatch];
	
	if (isWin)
	{
		[self postGameStatusNotification:Win];
	}
	else
	{
		[self postGameStatusNotification:Lose];
	}
}
- (void) turnOnStopWatch {
	elapseSecond = 0;
	secondTimer = [NSTimer scheduledTimerWithTimeInterval:1
												   target:self 
												 selector:@selector(increaseElapseSecond:)
												 userInfo:nil repeats:YES];
}
- (void) turnOffStopWatch {
	[secondTimer invalidate];
	secondTimer = nil;
}
- (void) resetStopWatch {	
	if (secondTimer)
	{
		[secondTimer invalidate];
	}
	
	secondTimer = nil;
	elapseSecond = -1;
	[self increaseElapseSecond:nil];
}

#pragma mark 雷区初始化
/*
- (NSMutableDictionary *)createRandomMine:(int)number forRange:(NSSize)size {
	NSMutableDictionary *randoms = [[NSMutableDictionary alloc] initWithCapacity:number];
	
	int mineCount = 0;
	while (mineCount < number)
	{
		int x = rand() % (int)size.width;
		int y = rand() % (int)size.height;
		
		NSString *key = [[[NSString alloc] initWithFormat:@"%d.%d", x, y] autorelease];
		
		NSValue *item = [randoms objectForKey:key];
		if (!item)
		{
			IntPoint point = GEMakeIntPoint(x, y);
			[randoms setValue:[NSValue value:&point withObjCType:@encode(IntPoint)] forKey:key];
			mineCount++;
		}
	}
	[randoms retain];
	return randoms;
}
*/
- (NSArray *)randomMine {
	NSMutableArray *array = [[NSMutableArray array] init];
	int mineCount = 0;
	while (mineCount < mineNumber)
	{
		int x = rand() % currentCols;
		int y = rand() % currentRows;
		
		if (![self isSignForField:FSMineField atXAxis:x andYAxis:y])
		{
			[self signToField:FSMineField atXAxis:x andYAxis:y toCancel:NO];
			IntPoint point = GEMakeIntPoint(x, y);
			[array addObject:[NSValue value:&point withObjCType:@encode(IntPoint)]];
			mineCount++;
		}
	}
	[array retain];
	return array;
}
// 布雷
- (void) mineInField:(NSSize) size {
	[self resetFieldDataWithWidth:size.width andHeight:size.height];
	
	[mineFieldImage release];
	mineFieldImage = [[NSImage alloc] initWithSize:NSMakeSize((int)(size.width * MineFieldWidth), (int)(size.height * MineFieldHeight))];
	gameIsOver = NO;
	gameStarted = NO;
	
	nonMineFieldCheckedCount = 0;
	
	[self resetStopWatch];
	
	NSArray *minePoss = [self randomMine];
	
	[self setFlagMineCount:mineNumber];
	
	[mineFieldImage lockFocus];
	
	NSRect drawingRect;
	drawingRect.size = NSMakeSize(MineFieldWidth, MineFieldHeight);
	for(int iw = 0; iw < size.width; iw++)
	{
		for(int ih = 0; ih < size.height; ih++)
		{
			drawingRect.origin.x = iw * MineFieldWidth;
			drawingRect.origin.y = ih * MineFieldHeight;
			
			NSRect imageRect = [(NSValue *)[materialCache objectForKey:MINEFIELD_KEY_BLOCK] rectValue];
			
			[materialImage drawInRect:drawingRect fromRect:imageRect operation:NSCompositeSourceOver fraction:1];
		}
	}
	
	[mineFieldImage unlockFocus];
	
	NSEnumerator *objectEnumerator = [minePoss objectEnumerator];
	id object = nil;
	while (object = [objectEnumerator nextObject])
	{
		IntPoint point;
		[(NSValue *) object getValue:&point];
		//NSLog(@"Calc around mine count base : {%d, %d}", point.x, point.y);
		
		for (int i = -1; i <= 1; i++) {
			for (int j = -1; j <= 1; j++) {
				//显示雷周围数字
				if (!(i == j && i == 0)){
					if (point.x - i < 0 || point.y - j < 0 || point.x - i >= currentCols || point.y - j >= currentRows) continue;
					int aroundMineCount = [self getAroundMineCountAtPoint:point.x-i andYAxis:point.y-j];
					aroundMineCount++;
					[self setAroundMineCountByCoordinate:aroundMineCount withXAxis:point.x-i andYAxis:point.y-j];
				}
			}
		}
	}
	
	if(minePositions)
	{
		[minePositions release];
	}
	minePositions = minePoss;
	[minePositions retain];
	
	[self postGameStatusNotification:OK];
	[self postNewGameNotification];
	
	//return mineField;
}
// Allocate new momery block to pointer fieldData
- (void)resetFieldDataWithWidth:(int)width andHeight:(int)height {
	if (fieldData)
	{
		[self releaseFieldData];
	}
	
	fieldData = (int **)malloc(width * sizeof(int));
	for (int i = 0; i < width; i++)
	{
		fieldData[i] = (int *)calloc(height, sizeof(int));
	}
	currentCols = width;
	currentRows = height;
}

#pragma mark 雷区回收
// To release the pointer fieldData's momery block
- (void)releaseFieldData {
	for (int i = 0; i < currentRows; i++)
	{
		free(fieldData[i]);
	}
	free(fieldData);
}

#pragma mark 雷区单个方格等坐标处理
// Set count of around a field
- (void)setAroundMineCountByCoordinate:(int)count withXAxis:(int)x andYAxis:(int)y {
	//int oldCount = HiWord(fieldData[x][y]);
	fieldData[x][y] = fieldData[x][y] ^ (HiWord(fieldData[x][y]) << 16);
	fieldData[x][y] = fieldData[x][y] | (count << 16);
	//int newCount = HiWord(fieldData[x][y]);
	//NSLog(@"Change point {%d, %d} around mine count: old count is %d, new count is %d", x, y, oldCount, newCount);
}

// Get count of around a field
- (int)getAroundMineCountAtPoint:(int)x andYAxis:(int)y {
	return HiWord(fieldData[x][y]);
}

- (void)signToField:(int)sign atXAxis:(int)x andYAxis:(int)y toCancel:(BOOL)cancel {
	if (cancel)
	{
		if (fieldData[x][y] & sign)
		{
			fieldData[x][y] = sign ^ fieldData[x][y];
		}
	}
	else
	{
		if (!(sign & fieldData[x][y]))
		{
			fieldData[x][y] = sign | fieldData[x][y];
		}
	}
}

- (BOOL)isSignForField:(int)sign atXAxis:(int)x andYAxis:(int)y {
	/*if ([self isPointInSafeBound:x andYAxis:y])*/	return (fieldData[x][y] & sign) != 0;
	
	//return NO;
}

- (BOOL)isPointInSafeBound:(int)x andYAxis:(int)y {
	return (x < 0 || y < 0 || x >= currentCols || y >= currentRows);
}

- (NSString *)imageKeyForPoint:(int)x andYAxis:(int)y {	
	NSString *key;
	switch ([self getAroundMineCountAtPoint:x andYAxis:y]) {
		case 0:
			key = MINEFIELD_KEY_BLANK;
			break;
		case 1:
			key = MINEFIELD_KEY_ONE;
			break;
		case 2:
			key = MINEFIELD_KEY_TWO;
			break;
		case 3:
			key = MINEFIELD_KEY_THREE;
			break;
		case 4:
			key = MINEFIELD_KEY_FOUR;
			break;
		case 5:
			key = MINEFIELD_KEY_FIVE;
			break;
		case 6:
			key = MINEFIELD_KEY_SIX;
			break;
		case 7:
			key = MINEFIELD_KEY_SEVEN;
			break;
		case 8:
			key = MINEFIELD_KEY_EIGHT;
			break;
		case 9:
			key = MINEFIELD_KEY_NINE;
			break;
		default:
			key = MINEFIELD_KEY_BLANK;
			break;
	}
	if ([self isSignForField:FSMineField atXAxis:x andYAxis:y])
		key = MINEFIELD_KEY_MINE;
	
	return key;
}


#pragma mark 处理用户动作
// 点击位置
- (int) hitTestPosition:(NSPoint)pos withCommand:(int)command {
	if (gameIsOver) return command;
	
	if (!gameStarted)
	{
		gameStarted = YES;
		[self turnOnStopWatch];
	}
	
	IntPoint fieldPos = [self convertToMineFieldPosition:pos];
	
	if ([self isPointInSafeBound:fieldPos.x andYAxis:fieldPos.y]) return command;
	
	//NSString *key = [[NSString alloc] initWithFormat:@"%d.%d", (int)fieldPos.x, (int)fieldPos.y];
	//MineFieldItem *item = [mineField objectForKey:key];
	int flagCount = 0;
	switch (command) {
		case MineCommandNormal:
			[self hitNormal:fieldPos];
			break;
		case MineCommandSetFlag:
			[self hitFlag:fieldPos];
			break;
		case MineCommandTip:
			[self hitTip:fieldPos toCancel:NO];
			break;
		case MineCommandCancelTip:
			[self hitTip:fieldPos toCancel:YES];
			break;
		case MineCommandFinishTip:
			flagCount = [self hitTip:fieldPos toCancel:YES];
			[self hitTipFinish:fieldPos flags:flagCount];
			break;
		default:
			break;
	}
	
	//[key release];
	return command;
}
- (void)hitNormal:(IntPoint)pos {
	int x = pos.x;
	int y = pos.y;
	
	BOOL isMineField = [self isSignForField:FSMineField atXAxis:x andYAxis:y];
	BOOL isChecked = [self isSignForField:FSChecked atXAxis:x andYAxis:y];
	BOOL isFlag = [self isSignForField:FSFlag atXAxis:x andYAxis:y];
	
	if (isChecked || isFlag) return;
	
	[self renderMineForPoint:pos toCheck:YES];
	nonMineFieldCheckedCount++;
	
	int aroundMineCount = [self getAroundMineCountAtPoint:x andYAxis:y];
	
	if (isMineField && !isFlag)
	{
		NSEnumerator *objectEnumerator = [minePositions objectEnumerator];
		NSValue *pointValue = nil;
		while (pointValue = [objectEnumerator nextObject]) {
			IntPoint loc;
			[pointValue getValue:&loc];
			BOOL isItemMineField = [self isSignForField:FSMineField atXAxis:loc.x andYAxis:loc.y];
			if (isItemMineField)
			{
				[self renderMineForPoint:loc toCheck:!(x == loc.x && y == loc.y)];
			}
		}
		nonMineFieldCheckedCount--;
		[self setGameOver:NO];
	}
	
	
	if (!isMineField && aroundMineCount == 0)
	{
		NSMutableArray *stack = [[NSMutableArray alloc] init];
		[stack addObjectsFromArray:[self minesAroundMineItem:pos includeChecked:NO]];
		while ([stack count] > 0) {
			//NSLog(@"stack count is %d", [stack count]);
			NSValue *pointValue = [stack objectAtIndex:0];
			IntPoint loc;
			[pointValue getValue:&loc];
			[stack removeObject:pointValue];
			//[pointValue release];
			[self renderMineForPoint:loc toCheck:YES];
			
			nonMineFieldCheckedCount++;
			if (![self isSignForField:FSMineField atXAxis:loc.x andYAxis:loc.y] && [self getAroundMineCountAtPoint:loc.x andYAxis:loc.y] == 0)
			{
				[stack addObjectsFromArray:[self minesAroundMineItem:loc includeChecked:NO]];
			}
		}
		[stack release];
	}
	
	if (nonMineFieldCheckedCount == (currentRows * currentCols - mineNumber))
	{
		[self setGameOver:YES];
		
		for (int i = 0; i < currentCols; i++)
		{
			for (int j = 0; j < currentRows; j++)
			{
				if ((fieldData[i][j] & FSMineField) && !(fieldData[i][j] & FSFlag))
				{
					[self renderToggleFlagForMine:GEMakeIntPoint(i, j)];
					[self decreaseFlagMineCount];
				}
			}
		}
	}
}
- (void)hitFlag:(IntPoint)pos {
	int x = pos.x;
	int y = pos.y;
	
	BOOL isChecked = fieldData[x][y] & FSChecked;
	BOOL isFlag = fieldData[x][y] & FSFlag;
	if (!isChecked)
	{
		[self renderToggleFlagForMine:pos];
		[self signToField:FSFlag atXAxis:x andYAxis:y toCancel:isFlag];
		//[item setIsFlag:![item isFlag]];
		isFlag = fieldData[x][y] & FSFlag;
		if (!isFlag)
		{
			[self increaseFlagMineCount];
		}
		else
		{
			[self decreaseFlagMineCount];
		}
	}
}
- (int)hitTip:(IntPoint)pos toCancel:(BOOL)cancel {	
	//	int x = pos.x;
	//	int y = pos.y;
	
	NSArray *mines = [self minesAroundMineItemIncludeSelf:pos includeChecked:NO];
	
	NSEnumerator *mineEnumerator = [mines objectEnumerator];
	
	NSValue *pointValue = nil;
	int flagCount = 0;
	while (pointValue = [mineEnumerator nextObject]) {
		IntPoint loc;
		[pointValue getValue:&loc];
		//[pointValue release];
		BOOL isFlag = fieldData[loc.x][loc.y] & FSFlag;
		BOOL isChecked = fieldData[loc.x][loc.y] & FSChecked;
		
		if (isFlag) flagCount++;
		if (isFlag || isChecked) continue;
		[self renderToggleTipForMine:loc toCancel:cancel];
	}
	//[mineEnumerator release];
	[mines release];
	return flagCount;
}
- (void)hitTipFinish:(IntPoint)pos flags:(int)flagCount {	

	if (flagCount > 0 && flagCount == [self getAroundMineCountAtPoint:pos.x andYAxis:pos.y])
	{		
		BOOL isSourceisChecked = fieldData[pos.x][pos.y] & FSChecked;
		if (!isSourceisChecked) return;
		NSArray *mines = [self minesAroundMineItemIncludeSelf:pos includeChecked:NO];
		NSValue *pointValue = nil;
		NSEnumerator *mineEnumerator = [mines objectEnumerator];
		while (pointValue = [mineEnumerator nextObject]) {
			IntPoint loc;
			[pointValue getValue:&loc];
			//[pointValue release];
			BOOL isFlag = fieldData[loc.x][loc.y] & FSFlag;
			BOOL isChecked = fieldData[loc.x][loc.y] & FSChecked;
			if (isFlag || isChecked) continue;
			[self hitNormal:loc];
		}
		//[mineEnumerator release];
		[mines release];
	}
}

#pragma mark 帮助方法
// 转换坐标到雷区坐标
- (IntPoint)convertToMineFieldPosition:(NSPoint)pos {
	NSNumber *x = [[[NSNumber alloc] initWithDouble:(((double)pos.x / (double)MineFieldWidth))] autorelease];
	NSNumber *y = [[[NSNumber alloc] initWithDouble:(((double)pos.y / (double)MineFieldHeight))] autorelease];
	
	return GEMakeIntPoint([x intValue], [y intValue]);
}
- (void)postNewGameNotification {
	[self postNotificationForKey:@"newGameNotification"];
}
- (void)postNotificationForKey:(NSString *)key {
	NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
	[nc postNotificationName:key object:nil];
}
- (void)postGameStatusNotification:(int)status {
	NSNotificationCenter *nc = [NSNotificationCenter defaultCenter];
	[nc postNotificationName:@"gameStatusChanged" object:[[NSNumber alloc] initWithInt:status]];
}
- (NSArray *)minesAroundMineItemIncludeSelf:(IntPoint)pos includeChecked:(BOOL)include {
	NSMutableArray *array = (NSMutableArray *)[self minesAroundMineItem:pos includeChecked:include];
	[array addObject:[NSValue value:&pos withObjCType:@encode(IntPoint)]];
	return array;
}
- (NSArray *)minesAroundMineItem:(IntPoint)pos includeChecked:(BOOL)include {
	int x = pos.x;
	int y = pos.y;
	
	//NSLog(@"Around base location {%d, %d}", x, y);
	NSMutableArray *mines = [[NSMutableArray alloc] init];
	for (int i = -1; i <= 1; i++) {
		for (int j = -1; j <= 1; j++) {
			//显示雷周围数字
			if (!(i == j && i == 0)){
				if (x - i < 0 || y - j < 0 || x - i >= currentCols || y - j >= currentRows) continue;
				
				IntPoint point = GEMakeIntPoint(x-i, y-j);
				//NSLog(@"New point {%d, %d} for around array", point.x, point.y);
				if (include)
				{	
					[mines addObject:[NSValue value:&point withObjCType:@encode(IntPoint)]];
					//NSLog(@"Add point {%d, %d} to around array", point.x, point.y);
				}
				else
				{
					if (!(fieldData[x - i][y - j] & FSChecked))
					{
						[mines addObject:[NSValue value:&point withObjCType:@encode(IntPoint)]];
						//NSLog(@"Add not checked point {%d, %d} to around array", point.x, point.y);
					}
				}
			}
		}
	}
	[mines retain];
	return mines;
}

#pragma mark 图片渲染方法
- (void)renderToggleTipForMine:(IntPoint)pos toCancel:(BOOL)cancel {
	int x = pos.x;
	int y = pos.y;
	
	NSRect drawingRect;
	
	drawingRect.size = NSMakeSize(MineFieldWidth, MineFieldHeight);
	drawingRect.origin.x = x * MineFieldWidth;
	drawingRect.origin.y = y * MineFieldHeight;
	
	NSString *minefield_key = MINEFIELD_KEY_BLANK;
	if (cancel)
	{
		minefield_key = MINEFIELD_KEY_BLOCK;
	}
	
	[mineFieldImage lockFocus];
	
	[materialImage drawInRect:drawingRect fromRect:[(NSValue *)[materialCache objectForKey:minefield_key] rectValue] operation:NSCompositeSourceOver fraction:1];
	
	[mineFieldImage unlockFocus];
}
- (void)renderToggleFlagForMine:(IntPoint)pos {
	int x = pos.x;
	int y = pos.y;
	
	NSRect drawingRect;
	
	drawingRect.size = NSMakeSize(MineFieldWidth, MineFieldHeight);
	drawingRect.origin.x = x * MineFieldWidth;
	drawingRect.origin.y = y * MineFieldHeight;
	
	[mineFieldImage lockFocus];
	if (fieldData[x][y] & FSFlag)
	{
		[materialImage drawInRect:drawingRect fromRect:[(NSValue *)[materialCache objectForKey:MINEFIELD_KEY_BLOCK] rectValue] operation:NSCompositeSourceOver fraction:1];
	}
	else
	{
		[materialImage drawInRect:drawingRect fromRect:[(NSValue *)[materialCache objectForKey:MINEFIELD_KEY_FLAG] rectValue] operation:NSCompositeSourceOver fraction:1];
	}
	[mineFieldImage unlockFocus];
}
- (void)renderMineForPoint:(IntPoint)pos toCheck:(BOOL)checked {

	int x = pos.x;
	int y = pos.y;
	
	BOOL isMineField = (fieldData[x][y] & FSMineField) != 0;
	NSString *imagekey = isMineField ? MINEFIELD_KEY_MINE : [self imageKeyForPoint:x andYAxis:y];

	[self signToField:FSChecked atXAxis:pos.x andYAxis:pos.y toCancel:NO];
	if (isMineField && !checked)
	{
		imagekey = MINEFIELD_KEY_MINECRASH;
	}
	
	NSRect drawingRect;
	
	drawingRect.size = NSMakeSize(MineFieldWidth, MineFieldHeight);
	drawingRect.origin.x = x * MineFieldWidth;
	drawingRect.origin.y = y * MineFieldHeight;
	
	NSRect imageRect = [(NSValue *)[materialCache objectForKey:imagekey] rectValue];
	
	[mineFieldImage lockFocus];
	
	// 画地雷和数字前，需要先把空地方画上去
	[materialImage drawInRect:drawingRect fromRect:[(NSValue *)[materialCache objectForKey:MINEFIELD_KEY_BLANK] rectValue] operation:NSCompositeSourceOver fraction:1];
	
	//设置雷区格子大小和位置
	if (!isMineField && [self getAroundMineCountAtPoint:x andYAxis:y] > 0)
	{
		// 如果周围数量大于0
		drawingRect.size = NSMakeSize(MineFieldNumberWidth, MineFieldNumberHeight);
		drawingRect.origin.x = x * MineFieldWidth + 2;
		drawingRect.origin.y = y * MineFieldHeight + 3;
	}
	[materialImage drawInRect:drawingRect fromRect:imageRect operation:NSCompositeSourceOver fraction:1];
	[mineFieldImage unlockFocus];
}



@end
